//
//  QRCodeViewController.swift
//  HMWeibo06
//
//  Created by apple on 15/5/15.
//  Copyright (c) 2015年 heima. All rights reserved.
//

import UIKit
import AVFoundation

class QRCodeViewController: UIViewController, UITabBarDelegate, AVCaptureMetadataOutputObjectsDelegate {

    // 冲击波的顶部约束
    @IBOutlet weak var topConstraint: NSLayoutConstraint!
    
    @IBOutlet weak var heightConstraint: NSLayoutConstraint!
    @IBOutlet weak var widthConstraint: NSLayoutConstraint!
    
    // 冲击波图像
    @IBOutlet weak var scanImageView: UIImageView!
    
    @IBOutlet weak var tabBar: UITabBar!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        tabBar.selectedItem = tabBar.items![0] as? UITabBarItem
    }
    
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        
        // 冲击波动画
        barAnimation()
        
        // 开始扫描
        scan()
    }
    
    // 冲击波动画
    private func barAnimation() {
        
        // 设置初始约束
        topConstraint.constant = -heightConstraint.constant
        // ** 强制更新布局
        view.layoutIfNeeded()
        
        UIView.animateWithDuration(3.0) {
            // 设置动画重复次数，一定要在内部
            UIView.setAnimationRepeatCount(MAXFLOAT)
            
            self.topConstraint.constant = self.heightConstraint.constant
            self.view.layoutIfNeeded()
        }
    }
    
    // TabBar代理方法
    func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem!) {

        // 根据选项，调整扫描框大小
        heightConstraint.constant = item.tag == 1 ? widthConstraint.constant * 0.5 : widthConstraint.constant
        
        // 核心动画中，是将动画添加到图层 － 停止一下动画
        self.scanImageView.layer.removeAllAnimations()
        // 再次启动动画
        barAnimation()
    }
    
    @IBAction func close() {
        dismissViewControllerAnimated(true, completion: nil)
    }
    
    // MARK: - 二维码扫描
    // 1. 拍摄会话 - 扫描的桥梁
    lazy var session: AVCaptureSession = {
        return AVCaptureSession()
    }()
    
    // 2. 输入设备 - 摄像头
    lazy var videoInput: AVCaptureDeviceInput? = {
        // 拿到摄像头设备
        let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
        
        if device == nil {
            return nil
        }
        
        return AVCaptureDeviceInput(device: device, error: nil)
    }()
    
    // 3. 输出数据 
    lazy var dataOutput: AVCaptureMetadataOutput = {
        return AVCaptureMetadataOutput()
    }()
    
    // 4. 预览视图
    lazy var previewLayer: AVCaptureVideoPreviewLayer = {
        // 必须指定一个 session
        let layer = AVCaptureVideoPreviewLayer(session: self.session)
        layer.frame = self.view.bounds
        
        return layer
    }()
    
    // 5. 绘图图层
    lazy var drawLayer: CALayer = {
        let layer = CALayer()
        layer.frame = self.view.bounds
        
        return layer
    }()
    
    // 开始扫描
    private func scan() {
        // 1. 判断会话能否添加输入设备
        if !session.canAddInput(videoInput) {
            println("无法添加输入设备")
            return
        }
        
        // 2. 判断能否添加输出设备
        if !session.canAddOutput(dataOutput) {
            println("无法添加输出设备")
            return
        }
        
        // 3. 添加设备
        session.addInput(videoInput)
        
        // 需要将设备添加到会话中，才能够获得 － 输出数据支持的格式
        println("前 - \(dataOutput.availableMetadataObjectTypes)")
        session.addOutput(dataOutput)
        println("后 - \(dataOutput.availableMetadataObjectTypes)")
        
        // 4. 设置输出识别的格式 & 代理
        dataOutput.metadataObjectTypes = dataOutput.availableMetadataObjectTypes
        dataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
        
        // 5. 启动会话
        session.startRunning()
        
        // 6. 添加预览图层
        view.layer.insertSublayer(drawLayer, atIndex: 0)
        view.layer.insertSublayer(previewLayer, atIndex: 0)
    }
    
    // MARK: - AVCaptureMetadataOutputObjectsDelegate
    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
        
        clearDrawLayer()
        
        for codeObject in metadataObjects {
            // 确保对象的类型 AVMetadataMachineReadableCodeObject
            if let obj = codeObject as? AVMetadataMachineReadableCodeObject {
                // 一定需要使用预览图层转换对象，才能够得到视图上的坐标
                let object = previewLayer.transformedMetadataObjectForMetadataObject(obj) as! AVMetadataMachineReadableCodeObject
                
                drawCorners(object)
                
                println(object.stringValue)
            }
        }
    }
    
    /// 清除绘图图层的子图层
    private func clearDrawLayer() {
        
        // 1. 需要判断是否有子图层
        if drawLayer.sublayers == nil {
            return
        }
        
        // 2. 删除所有子涂层
        for l in drawLayer.sublayers {
            l.removeFromSuperlayer()
        }
    }
    
    /// 绘制边线
    private func drawCorners(codeObject: AVMetadataMachineReadableCodeObject) {
        
        if codeObject.corners.count == 0 {
            return
        }
        
        // 创建 `shape` Layer 专门用来画图的
        let layer = CAShapeLayer()
        
        // 边线颜色
        layer.strokeColor = UIColor.greenColor().CGColor
        // 填充颜色
        layer.fillColor = UIColor.clearColor().CGColor
        // 线宽
        layer.lineWidth = 4.0
        // 设置路径
        // corners 中保存的是 CFDictionary objects 数组
        layer.path = createPath(codeObject.corners).CGPath
        
        drawLayer.addSublayer(layer)
    }
    
    private func createPath(points: NSArray) -> UIBezierPath {
        
        let path = UIBezierPath()
        var point = CGPoint()
        
        var index = 0
        
        // 1. 移动到第一个点
        CGPointMakeWithDictionaryRepresentation(points[index++] as! CFDictionaryRef, &point)
        path.moveToPoint(point)
        
        // 2. 循环遍历剩下的点
        while index < points.count {
            CGPointMakeWithDictionaryRepresentation(points[index++] as! CFDictionaryRef, &point)
            path.addLineToPoint(point)
        }
        
        // 3. 关闭路径，从起始点到结束点，连一根线
        path.closePath()
        
        return path
    }
}
